home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume9 / xscreen / part02 < prev    next >
Encoding:
Internet Message Format  |  1987-04-19  |  34.3 KB

  1. Subject:  v09i053:  Screensaver for X window system, Part02/02
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.TMC.COM
  4.  
  5. Submitted by: edmoy@opal.Berkeley.EDU
  6. Mod.sources: Volume 9, Issue 53
  7. Archive-name: xscreen/Part02
  8.  
  9. This is part 2/2 of screensaver, a display blanking and lock screen
  10. program for X version 10, release 4.  Enjoy.
  11.  
  12. Edward Moy
  13. Academic Computing Services
  14. University of California
  15. Berkeley, CA  94720
  16.  
  17. edmoy@opal.Berkeley.EDU
  18. ucbvax!opal!edmoy
  19.  
  20. #! /bin/sh
  21. # This is a shell archive, meaning:
  22. # 1. Remove everything above the #! /bin/sh line.
  23. # 2. Save the resulting text in a file.
  24. # 3. Execute the file with /bin/sh (not csh) to create the files:
  25. #    screensaver.1
  26. #    screensaver.c
  27. if test -f screensaver.1
  28. then
  29.     echo shar: will not overwrite existing file "'screensaver.1'"
  30. else
  31. echo 'x - screensaver.1'
  32. cat << \RAZZLE!DAZZLE > screensaver.1
  33. .TH SCREENSAVER 1 "Jan 1987" "X Version 10"
  34. .SH NAME
  35. screensaver \- blanks display
  36. .SH SYNOPSIS
  37. .B screensaver
  38. [
  39. .B \-L
  40. tty
  41. ] [
  42. .B \-b 
  43. bitmap_file
  44. ] [
  45. .B \-f
  46. font
  47. ] [
  48. .B \-i
  49. file
  50. ] [
  51. .B \-l
  52. ] [
  53. .B \-t
  54. seconds
  55. ] [
  56. geometry
  57. ] [
  58. display
  59. ]
  60. .SH DESCRIPTION
  61. .I Screensaver
  62. is a client application running under the X windowing system that blanks
  63. the display after a certain period of idle time; 5 minutes is the default
  64. or set by the
  65. .B \-t
  66. option.
  67. The display is restored by pressing a key or a mouse button.
  68. Unlike the screensaver function built into the X server, this program
  69. only detects input activity (rather than output to the display also), so
  70. that screensaving works even with clocks, load monitor, etc. running.
  71. .PP
  72. When executed,
  73. .I screensaver
  74. splits off a child process to run in the background.
  75. The child first reads in a file in
  76. .IR bitmap (1)
  77. format; the default file is
  78. .B /usr/local/lib/X/Xscreensaver
  79. but can be specified by the
  80. .B \-b
  81. option.
  82. This bitmap is bounced (slowly) around the display, and at random times, the
  83. angle of reflection will also be at random.
  84. .PP
  85. If a file exists with the same name as the bitmap file, but with
  86. .B \&.pm
  87. appended to it, then this bitmap is also read in.
  88. The original bitmap is displayed during AM hours and this second bitmap,
  89. during PM hours.
  90. .PP
  91. If the file is not in
  92. .IR bitmap (1)
  93. format, it is assumed to be a sequence of lines containing 4 items, separated
  94. by white space.
  95. The first item is the name of another file (which must be in
  96. .IR bitmap (1)
  97. format).
  98. If a relative pathname is specified, it is relative to the directory of
  99. the original file.
  100. The second item on the line is the color of this part of the bitmap, and
  101. the last two items are the relative x and y coordinate of this bitmap to
  102. the whole bitmap.
  103. Thus, a full color bitmap can be produced.
  104. .PP
  105. By default, the font used to display the time while the bitmap is being
  106. bounced around the screen is
  107. .BR 9x15 .
  108. An alternate font may be specified by using the
  109. .B \-f
  110. option.
  111. .PP
  112. The
  113. .B \-l
  114. option sets the auto-lock feature, that requests the password of the
  115. current user before un-blanking the screen (the root password will
  116. always unlock the screen).
  117. .PP
  118. When the X window system and
  119. .I screensaver
  120. are started at boot time, the
  121. .B \-L
  122. flag should be given with the tty of the login window.
  123. This automatically disables the locking feature if no one is logged
  124. into the login window.
  125. .PP
  126. Normally,
  127. .I screensaver
  128. checks the master end of all pseudo-tty's to determine input activity.
  129. This is imperfect, as not all applications use pseudo-tty's and mouse
  130. activity is not considered at all.
  131. If the
  132. .B \-i
  133. option is specified to the X server, then it will update the
  134. file changed time on the specified file when any keyboard or mouse
  135. input occurs.
  136. Specifying the same
  137. .B \-i
  138. option and file to
  139. .I screensaver
  140. will then cause it to monitor this file and determine when to blank the screen.
  141. This option also allows
  142. .I screensaver
  143. to run on hosts with multiple displays, as each separate X server could
  144. specify a different file to update.
  145. .PP
  146. The initial position of the icon is in the upper left-hand corner of the
  147. display, but can be set to any other position by using the
  148. .I geometry
  149. argument:
  150. .TP \w'\fB=+\fIx\fB+\fIy\fR'u+4n
  151. \fB=+\fIx\fB+\fIy\fR
  152. (+\fIx\fP,+\fIy\fP) from upper lefthand corner
  153. .TP
  154. \fB=+\fIx\fB\-\fIy\fR
  155. (+\fIx\fP,\-\fIy\fP) from lower lefthand corner
  156. .TP
  157. \fB=\-\fIx\fB+\fIy\fR
  158. (\-\fIx\fP,+\fIy\fP) from upper righthand corner
  159. .TP
  160. \fB=\-\fIx\fB\-\fIy\fR
  161. (\-\fIx\fP,\-\fIy\fP) from lower righthand corner
  162. .PP
  163. The display
  164. .I screensaver
  165. will blank is specified in the
  166. .B DISPLAY
  167. environment variable, or as
  168. .I display
  169. on the command line.
  170. .PP
  171. If either the left or right button of the mouse is released while the cursor
  172. is in the icon, the display will be instantly blanked.
  173. If the middle button is pressed, a menu is displayed, allowing various
  174. parameters to be set, such as auto-locking on timeouts and turning on and
  175. off the automatic timeouts.
  176. .SH FILES
  177. .TP \w'/usr/local/lib/X/Xscreensaver.pm'u+4n
  178. /usr/local/lib/X/Xscreensaver
  179. Default bitmap.
  180. .TP
  181. /usr/local/lib/X/Xscreensaver.pm
  182. Default PM hours bitmap (optional).
  183. .SH SEE ALSO
  184. bitmap(1)
  185. .SH AUTHOR
  186. Written by Edward Moy, Academic Computing Services, University of
  187. California at Berkeley.
  188. RAZZLE!DAZZLE
  189. fi    # End screensaver.1
  190. if test -f screensaver.c
  191. then
  192.     echo shar: will not overwrite existing file "'screensaver.c'"
  193. else
  194. echo 'x - screensaver.c'
  195. cat << \RAZZLE!DAZZLE > screensaver.c
  196. /*
  197.  * screensaver - blanks displays under X window system
  198.  *    (requires X version 10)
  199.  *
  200.  * Written by:
  201.  *    Edward Moy
  202.  *    Academic Computing Services
  203.  *    University of California at Berkeley
  204.  */
  205. #include <ctype.h>
  206. #include <stdio.h>
  207. #include <signal.h>
  208. #include <strings.h>
  209. #include <pwd.h>
  210. #include <setjmp.h>
  211. #include <utmp.h>
  212. #include <errno.h>
  213. #include <sys/types.h>
  214. #include <sys/stat.h>
  215. #include <sys/ioctl.h>
  216. #include <sys/time.h>
  217. #include <sys/file.h>
  218. #include <X/Xlib.h>
  219. #include "menu.h"
  220. #include "arrow"
  221. #include "arrowmask"
  222.  
  223. #define    AnyButtonMask    (LeftMask | MiddleMask | RightMask)
  224. #define    BITMAPOPENERR    0
  225. #define    BITMAPOK    1
  226. #define    BITSPERBYTE    8
  227. #define    BITSPERSHORT    (BITSPERBYTE * sizeof(short))
  228. #define    BOTTOM        3
  229. #define    CURHEIGHT    16
  230. #define    CURWIDTH    16
  231. #define    DEFAULTHEIGHT    38
  232. #define    DEFAULTWIDTH    48
  233. #define    DELTA        4
  234. #define    FALSE        0
  235. #define    IDLETIME    300
  236. #define    IMAGESPERSEC    5
  237. #define    LEFT        0
  238. #define    MICROSEC    (1000000 / IMAGESPERSEC)
  239. #define    NWALLS        4
  240. #define    PAD        4
  241. #define    PASSWORDLEN    9
  242. #define    RANCNTMAX    32
  243. #define    RIGHT        2
  244. #define    SELECTERR    -1
  245. #define SINN        20
  246. #define    TIMEOUT        0
  247. #define    TOP        1
  248. #define    TRUE        1
  249. #define    USERLEN        5
  250. #define    VERIFYTIMEOUT    45
  251.  
  252. #define    max(a,b)    ((a) > (b) ? (a) : (b))
  253. #define    rangex(x)    ((x) >= areawidth ? areawidth-1 : ((x) < 0 ? 0 : (x)))
  254. #define    rangey(y)    ((y) >= areaheight ? areaheight-1 : ((y) < 0 ? 0 : (y)))
  255. #define    xmove(x)    (signx * sin1000[SINN - sinindex] * x / 1000 + x0)
  256. #define    ymove(y)    (signy * sin1000[sinindex] * y / 1000 + y0)
  257.  
  258. #define    MENU_ONOFF    0
  259. #define    MENU_AUTOLOCK    (MENU_ONOFF+1)
  260. #define    MENU_LINE    (MENU_AUTOLOCK+1)
  261. #define    MENU_BLANK    (MENU_LINE+1)
  262. #define    MENU_LOCK    (MENU_BLANK+1)
  263. #define    MENU_LINE2    (MENU_LOCK+1)
  264. #define    MENU_EXIT    (MENU_LINE2+1)
  265.  
  266. struct bm {
  267.     struct bm *next;
  268.     short *bits;
  269.     int x;
  270.     int y;
  271.     int width;
  272.     int height;
  273.     int color;
  274. };
  275.  
  276. int am;
  277. int amicon;
  278. int areaheight;
  279. int areawidth;
  280. Cursor arrow;
  281. int autolock;
  282. char *bitmap_file = XSCREENSAVER;
  283. int bitmap_height;
  284. int bitmap_width;
  285. Window black;
  286. Cursor blackcursor;
  287. int center;
  288. FILE *console = stderr;
  289. short *cursor_bits;
  290. int cursor_height;
  291. int cursor_width;
  292. FontInfo *finfo;
  293. Font font;
  294. int fontheight;
  295. char *fontname = "9x15";
  296. int halfwidth;
  297. Window icon;
  298. int iconx = DELTA;
  299. int idletime = IDLETIME;
  300. struct timeval idletimeout = {
  301.     IDLETIME,
  302.     0,
  303. };
  304. Pixmap image;
  305. int imageheight;
  306. Pixmap imagepm;
  307. int imagewidth;
  308. int locked;
  309. char *mtext[] = {
  310.     "Screensaving",
  311.     "Auto-Lock",
  312.     "-",
  313.     "Blank Screen",
  314.     "Lock Screen",
  315.     "-",
  316.     "Exit",
  317.     0,
  318. };
  319. struct timeval movetimeout = {
  320.     0,
  321.     MICROSEC,
  322. };
  323. Menu *menu;
  324. char *myname;
  325. int mynamelen;
  326. int newtime;
  327. Vertex outline[5] = {
  328.     {0, 0, VertexDontDraw},
  329.     {0, 0, VertexRelative},
  330.     {0, 0, VertexRelative},
  331.     {0, 0, VertexRelative},
  332.     {0, 0, VertexRelative},
  333. };
  334. char password[] = "Password:";
  335. int passwordwidth;
  336. struct passwd *pw;
  337. int rancnt;
  338. char rootpasswd[32];
  339. int screensave = TRUE;
  340. int sin1000[SINN + 1] = {
  341.     258, 309, 358, 406, 453, 500, 544, 587, 629, 669,
  342.     707, 743, 777, 809, 838, 866, 891, 913, 933, 951,
  343.     965,
  344. };
  345. int sinindex;
  346. int signx;
  347. int signy;
  348. int spacewidth;
  349. int step;
  350. Pixmap text;
  351. int timemove;
  352. struct timeval *timeout;
  353. struct itimerval timer;
  354. char timestr[] = "00:00";
  355. int timewidth;
  356. char *tty;
  357. char user[] = "User:";
  358. int userwidth;
  359. jmp_buf verifyjmp;
  360. struct timeval verifytimeout = {
  361.     VERIFYTIMEOUT,
  362.     0,
  363. };
  364. int X_input_fd = -1;
  365. int x0;
  366. int xlast;
  367. int y0;
  368. int ylast;
  369.  
  370. extern int errno;
  371.  
  372. main(argc, argv)
  373. char **argv;
  374. {
  375.     register XEvent *ev;
  376.     register int i, maxfds, status, readfds;
  377.     register char *cp, *disp = NULL, *geom = NULL, *Xin = NULL;
  378.     register Display *display;
  379.     int rfds;
  380.     XEvent xevent;
  381.  
  382.     if(myname = rindex(argv[0], '/'))
  383.         myname++;
  384.     else
  385.         myname = argv[0];
  386.     mynamelen = strlen(myname);
  387.     if(cp = XGetDefault(myname, "AutoLock"))
  388.         if(strcmp(cp, "on") == 0)
  389.             autolock = TRUE;
  390.     if(cp = XGetDefault(myname, "BitmapFile"))
  391.         bitmap_file = cp;
  392.     if(cp = XGetDefault(myname, "Font"))
  393.         fontname = cp;
  394.     if(cp = XGetDefault(myname, "IdleTime"))
  395.         idletime = idletimeout.tv_sec = atoi(cp);
  396.     if(cp = XGetDefault(myname, "InputTrack"))
  397.         Xin = cp;
  398.     while(--argc > 0) {
  399.         if(**++argv == '-')
  400.             switch((*argv)[1]) {
  401.              case 'L':    /* login tty */
  402.                 if(--argc <= 0)
  403.                     fatal("No argument for -L");
  404.                 if(strncmp(tty = *++argv, "tty", 3) != 0)
  405.                     fatal("Illegal argument for -L");
  406.                 break;
  407.              case 'b':    /* alternate bitmap file */
  408.                 if(--argc <= 0)
  409.                     fatal("No argument for -b");
  410.                 bitmap_file = *++argv;
  411.                 break;
  412.              case 'f':    /* alternate font */
  413.                 if(--argc <= 0)
  414.                     fatal("No argument for -f");
  415.                 fontname = *++argv;
  416.                 break;
  417.              case 'i':    /* X input track file */
  418.                 if(--argc <= 0)
  419.                     fatal("No argument for -i");
  420.                 Xin = *++argv;
  421.                 break;
  422.              case 'l':    /* set auto-lock */
  423.                  autolock = TRUE;
  424.                 break;
  425.              case 't':    /* different idle time */
  426.                 if(--argc <= 0)
  427.                     fatal("No argument for -t");
  428.                 if((idletime = idletimeout.tv_sec =
  429.                  atoi(*++argv)) <= 0)
  430.                     fatal("Illegal argument for -t");
  431.                 break;
  432.              default:
  433.                 fatal("Unknown option");
  434.             }
  435.         else if(**argv == '=')
  436.             geom = *argv;
  437.         else break;
  438.     }
  439.     if(argc > 0 && index(disp = *argv, ':') == NULL)
  440.         fatal("Illegal display");
  441.     if((pw = getpwnam("root")) && *pw->pw_passwd)
  442.         strcpy(rootpasswd, pw->pw_passwd);
  443.     if(!tty) {
  444.         if((pw = getpwuid(getuid())) == NULL)
  445.             fatal("No password entry");
  446.         endpwent();
  447.     }
  448.     /*
  449.      * Let the parent exit; the child will do the real work.
  450.      */
  451. #ifndef DEBUG
  452.     if((i = fork()) < 0)
  453.         fatal("Can't fork");
  454.     if(i)    /* the parent */
  455.         exit(0);
  456. #endif DEBUG
  457.     signal(SIGINT, SIG_IGN);
  458.     signal(SIGQUIT, SIG_IGN);
  459.     nice(10);
  460.     if(tty) {
  461.         /*
  462.          * Detach the controlling tty.
  463.          */
  464.         for (i = 0; i < 10; i++)
  465.             (void) close(i);
  466.         (void) open("/", 0);
  467.         (void) dup2(0, 1);
  468.         (void) dup2(0, 2);
  469.         if((i = open("/dev/tty", 2)) >= 0) {
  470.             ioctl(i, TIOCNOTTY, 0);
  471.             (void) close(i);
  472.         }
  473.         console = NULL;
  474.         signal(SIGHUP, SIG_IGN);
  475.     }
  476. #ifdef DEBUG
  477.     freopen("ss.db", "w", stderr);
  478.     setlinebuf(stderr);
  479. #endif DEBUG
  480.     /*
  481.      * Wait until the server is active.
  482.      */
  483.     while((display = XOpenDisplay(disp)) == NULL)
  484.         sleep(10);
  485.     if(Xin)
  486.         X_input_fd = open(Xin, O_RDONLY, 0);
  487.     init(geom);
  488.     /*
  489.      * Initialize the select system call's maximum file
  490.      * descriptor number to be one more than the file descriptor
  491.      * number of the X connection.
  492.      */
  493.     maxfds = dpyno() + 1;
  494.     /*
  495.      * Use the select system call on the file descriptor in
  496.      * the display structure to determine if there is work
  497.      * to be done.  If not block until timeout.  Remember to
  498.      * reset the file descriptor before each select.
  499.      */
  500.     readfds = 1 << dpyno();
  501.     /*
  502.      * The main process loop.  After the first sleep period, we check if
  503.      * the master ends of all ptys have been written to within the idle
  504.      * period.  If not, we blank the screen.  Otherwise we calculate
  505.      * when we should wake up again to check.
  506.      */
  507.     timeout = screensave ? &idletimeout : NULL;
  508.     ev = &xevent;
  509.     XSync(TRUE);
  510.     for( ; ; ) {
  511.         if(XPending()) {
  512.             XNextEvent(ev);
  513.             switch(ev->type) {
  514.              case UnmapWindow:
  515.                 /*
  516.                  * If we are still in movetimeout mode, then
  517.                  * something unmapped use.  If we are locked
  518.                  * remap the black window and go through the
  519.                  * verification process.
  520.                  */
  521.                 if(timeout == &movetimeout) {
  522.                     if(locked) {
  523.                         XUnmapWindow(icon);
  524.                         XMapWindow(black);
  525.                     }
  526.                     restorescreen();
  527.                 }
  528.                 break;
  529.              case ButtonReleased:
  530.              case KeyPressed:
  531.                 /*
  532.                  * Restore the screen and map the icon if we are
  533.                  * in move timeout mode.
  534.                  */
  535.                 if(ev->window == black) {
  536.                     if(timeout == &movetimeout)
  537.                         restorescreen();
  538.                 } else if(ev->type != ButtonReleased ||
  539.                  (((XButtonEvent *)ev)->detail & 0xff)
  540.                  != MiddleButton) {
  541.                     XUnmapWindow(icon);
  542.                     blank(autolock);
  543.                     i = IMAGESPERSEC;
  544.                 }
  545.                 break;
  546.              case ButtonPressed:
  547.                 /*
  548.                  * For the icon, do the menu if middle button.
  549.                  */
  550.                 if(ev->window != black &&
  551.                  (((XButtonEvent *)ev)->detail & 0xff)
  552.                  == MiddleButton)
  553.                     i = domenu(ev);
  554.                 break;
  555.              case ExposeWindow:
  556.                 if(ev->window == black) {
  557.                     /*
  558.                      * If we are still doing an idle
  559.                      * timeout, a window manager must
  560.                      * have deiconified us.
  561.                      */
  562.                     if(timeout == &idletimeout) {
  563.                         blank(autolock);
  564.                         i = IMAGESPERSEC;
  565.                     }
  566.                 } else
  567.                     /*
  568.                      * refresh the icon
  569.                      */
  570.                     refreshicon();
  571.                 break;
  572.             }
  573.         } else {
  574.             rfds = readfds;
  575.             if((status = select(maxfds, &rfds, NULL, NULL, timeout))
  576.              < 0) {
  577.                 if(errno != EINTR)
  578.                     fatal("Error in select");
  579.             } else if(status == TIMEOUT) {
  580.                 if(timeout == &idletimeout) {
  581.                     if((timeout->tv_sec = tryagain()) == 0){
  582.                         XUnmapWindow(icon);
  583.                         blank(autolock);
  584.                         i = IMAGESPERSEC;
  585.                     }
  586.                 } else {
  587.                     drawimage();
  588.                     if(--i <= 0) {
  589.                         XRaiseWindow(black);
  590.                         XSync(FALSE);
  591.                         newtimestr();
  592.                         i = IMAGESPERSEC;
  593.                     }
  594.                 }
  595.             }
  596.         }
  597.     }
  598. }
  599.  
  600. /*
  601.  * init() does most of the window/bitmap initialization.
  602.  */
  603. init(geom)
  604. char *geom;
  605. {
  606.     register Bitmap pic, cur;
  607.     register int i;
  608.     register Pixmap *ip;
  609.     struct bm *head, *headam, *headpm;
  610.     register int xx, yy, compensate = FALSE;
  611.     int x = 0;
  612.     int y = 0;
  613.     int w, h;
  614.     char pmname[128];
  615.     extern int onalarm();
  616.  
  617.     /*
  618.      * Make a window the size of the root window, so that it will cover up
  619.      * the entire screen.
  620.      */
  621. #ifdef DEBUG
  622.     if((black = XCreateWindow(RootWindow, 0, 0, DisplayWidth(),
  623.      DisplayHeight() / 2, 0, (Pixmap)0, BlackPixmap)) == NULL)
  624. #else DEBUG
  625.     if((black = XCreateWindow(RootWindow, 0, 0, DisplayWidth(),
  626.      DisplayHeight(), 0, (Pixmap)0, BlackPixmap)) == NULL)
  627. #endif DEBUG
  628.         fatal("Can't create window");
  629.     XSelectInput(black, KeyPressed | ButtonPressed | ButtonReleased |
  630.      ExposeWindow | UnmapWindow);
  631.     /*
  632.      * Make an all black cursor, which will be invisible against the
  633.      * window's black tile.
  634.      */
  635.     XQueryCursorShape(CURWIDTH, CURHEIGHT, &cursor_width, &cursor_height);
  636.     if((cursor_bits = (short *)calloc((cursor_width + (BITSPERSHORT - 1))
  637.      / BITSPERSHORT * cursor_height, sizeof(short))) == NULL)
  638.         fatal("No memory for cursor");
  639.     if((cur = XStoreBitmap(cursor_width, cursor_height, cursor_bits)) ==
  640.      NULL)
  641.         fatal("Can't make cursor");
  642.     free(cursor_bits);
  643.     if((blackcursor = XStoreCursor(cur, cur, 0, 0, BlackPixel, BlackPixel,
  644.      GXcopy)) == NULL)
  645.         fatal("Can't build cursor");
  646.     XFreeBitmap(cur);
  647.     XDefineCursor(black, blackcursor);
  648.     /*
  649.      * Now get the font and the font info for the characters of the time.
  650.      */
  651.     if((finfo = XOpenFont(fontname)) == NULL)
  652.         fatal("Can't get font");
  653.     font = finfo->id;
  654.     fontheight = finfo->height + DELTA;
  655.     outline[4].y = -(outline[2].y = 5 * finfo->height + 5);
  656.     /*
  657.      * We create the image by reading in the bitmap(s) and making the
  658.      * icon the right size.  Then we draw the image in the icon and save it
  659.      * with addition black space space all around (except the top), so
  660.      * that we can just redraw the image, which will overwrite the
  661.      * previous image (no erasing is needed).
  662.      */
  663.     setupimage(bitmap_file, &bitmap_width, &bitmap_height, &headam, FALSE);
  664.     strcpy(pmname, bitmap_file);
  665.     strcat(pmname, ".pm");
  666.     if(setupimage(pmname, &w, &h, &headpm, TRUE)) {
  667.         if(w > bitmap_width)
  668.             bitmap_width = w;
  669.         if(h > bitmap_height)
  670.             bitmap_height = h;
  671.     } else
  672.         headpm = NULL;
  673.     x0 = y0 = DELTA;
  674.     /*
  675.      * This is how far to move horizontally from the upper left
  676.      * corner of the bitmap to the upper left corner of the time
  677.      * string.
  678.      */
  679.     timemove = (bitmap_width - (timewidth = XStringWidth(timestr,
  680.      finfo, 0, 0))) / 2;
  681.     halfwidth = XStringWidth("0", finfo, 0, 0) / 2;
  682.     if(timemove < 0) {
  683.         compensate = TRUE;
  684.         iconx = (x0 -= timemove);
  685.         timemove = 0;
  686.     }
  687.     /*
  688.      * The image will be a pixmap containing the bitmap and room for
  689.      * the time string.  It will be further enlarged with a black
  690.      * border so that we can simply redraw the image, which will
  691.      * overlap the image one step size back.
  692.      */
  693.     imagewidth = max(bitmap_width, timewidth) + 2 * DELTA;
  694.     imageheight = bitmap_height + DELTA;
  695.     /*
  696.      * Determine the position of the icon.
  697.      */
  698.     if(geom && (i = XParseGeometry(geom, &x, &y, &w, &h))) {
  699.         if((i & XValue) && (i & XNegative))
  700.             x = DisplayWidth() + x - imagewidth - 2 * PAD;
  701.         if((i & YValue) && (i & YNegative))
  702. #ifdef DEBUG
  703.             y = DisplayHeight() / 2 + y - imageheight - 2 * PAD -
  704.              DELTA;
  705. #else DEBUG
  706.             y = DisplayHeight() + y - imageheight - 2 * PAD - DELTA;
  707. #endif DEBUG
  708.     }
  709.     /*
  710.      * Create the icon window, positioned by the geom string, but
  711.      * compensate so that the icon is initially all on the screen.
  712.      * This is so we can make a pixmap of the image.  The window is
  713.      * then reset to what the user wants.
  714.      */
  715.     if((xx = x) < 0) {
  716.         compensate = TRUE;
  717.         xx = 0;
  718.     }
  719.     if((yy = y) < 0) {
  720.         compensate = TRUE;
  721.         yy = 0;
  722.     }
  723.     if(xx > (i = DisplayWidth() - imagewidth - 2 * PAD)) {
  724.         compensate = TRUE;
  725.         xx = i;
  726.     }
  727.     if(yy > (i = DisplayHeight() - imageheight - 2 * PAD)) {
  728.         compensate = TRUE;
  729.         yy = i;
  730.     }
  731.     if((icon = XCreateWindow(RootWindow, xx, yy, imagewidth, imageheight +
  732.      DELTA, PAD, WhitePixmap, BlackPixmap)) == NULL)
  733.         fatal("Can't create icon window");
  734.     if(arrow = XCreateCursor(arrow_width, arrow_height, arrow_bits,
  735.      arrowmask_bits, arrow_x_hot, arrow_y_hot, BlackPixel, WhitePixel,
  736.      GXcopy))
  737.         XDefineCursor(icon, arrow);
  738.     /*
  739.      * Grab the server to make sure we get the icon done properly.
  740.      */
  741. #ifndef DEBUG
  742.     XGrabServer();
  743. #endif DEBUG
  744.     XMapWindow(icon);
  745.     if(headpm) {
  746.         signal(SIGALRM, SIG_IGN);
  747.         seticonalarm();
  748.         if(amicon) {
  749.             head = headpm;
  750.             ip = &imagepm;
  751.         } else {
  752.             head = headam;
  753.             ip = ℑ
  754.         }
  755.         drawbm(head);
  756.         *ip = XPixmapSave(icon, 0, DELTA, imagewidth, imageheight);
  757.         XClear(icon);
  758.         if(i = amicon) {
  759.             head = headam;
  760.             ip = ℑ
  761.         } else {
  762.             head = headpm;
  763.             ip = &imagepm;
  764.         }
  765.     } else {
  766.         head = headam;
  767.         ip = ℑ
  768.     }
  769.     drawbm(head);
  770.     *ip = XPixmapSave(icon, 0, DELTA, imagewidth, imageheight);
  771.     if(!image && !imagepm)
  772.         fatal("Can't make image");
  773.     if(!image) {
  774.         image = imagepm;
  775.         imagepm = NULL;
  776.     }
  777. #ifndef DEBUG
  778.     XUngrabServer();
  779. #endif DEBUG
  780.     XSelectInput(icon, ExposeWindow | ButtonPressed | ButtonReleased);
  781.     XSetIconWindow(black, icon);
  782.     if(compensate) {
  783.         XConfigureWindow(icon, x, y, bitmap_width + 2 * DELTA,
  784.          bitmap_height + 2 * DELTA);
  785.         refreshicon();
  786.     }
  787.     signal(SIGALRM, onalarm);
  788.     if(imagepm) {
  789.         seticonalarm();
  790.         if(i != amicon)
  791.             refreshicon();
  792.     }
  793.     /*
  794.      * The area is the size on the rectangle that the image will
  795.      * bounce in. Since everything is with reference to the upper
  796.      * left corner, all we need to do is prevent the upper left
  797.      * corner of the image from going outside the area bounds.
  798.      */
  799.     areawidth = DisplayWidth() - imagewidth;
  800. #ifdef DEBUG
  801.     areaheight = DisplayHeight() / 2 - imageheight - fontheight;
  802. #else DEBUG
  803.     areaheight = DisplayHeight() - imageheight - fontheight;
  804. #endif DEBUG
  805.     spacewidth = XStringWidth("n", finfo, 0, 0);
  806.     passwordwidth = XStringWidth(password, finfo, 0, 0) + 2 * spacewidth;
  807.     userwidth = XStringWidth(user, finfo, 0, 0) + spacewidth;
  808.     signx = (random() & 1) ? 1 : -1;
  809.     signy = (random() & 1) ? 1 : -1;
  810. }
  811.  
  812. drawbm(bp)
  813. register struct bm *bp;
  814. {
  815.     register struct bm *np;
  816.     register Bitmap mask;
  817.  
  818.     if(bp->bits == NULL) {    /* default */
  819.         XPixSet(icon, x0, y0, DEFAULTWIDTH, DEFAULTHEIGHT, WhitePixel);
  820.         XPixSet(icon, x0 + PAD, y0 + PAD, DEFAULTWIDTH - 2 * PAD,
  821.          DEFAULTHEIGHT - 2 * PAD, BlackPixel);
  822.         free((char *)bp);
  823.         return;
  824.     }
  825.     while(bp) {
  826.         if(mask = XStoreBitmap(bp->width, bp->height, bp->bits)) {
  827.             XPixFill(icon, x0 + bp->x, y0 + bp->y, bp->width,
  828.              bp->height, bp->color, mask, GXcopy, AllPlanes);
  829.             XFreeBitmap(mask);
  830.         }
  831.         np = bp->next;
  832.         free((char *)bp);
  833.         bp = np;
  834.     }
  835. }
  836.  
  837. /*
  838.  * restorescreen() unmaps the black window, maps the icon window and sets the
  839.  * idle timeout.  If locked, then verify password.
  840.  */
  841. restorescreen()
  842. {
  843.     if(locked) {
  844.         if(verify()) {
  845.             XUngrabMouse();
  846.             XSync(TRUE);
  847.             locked = FALSE;
  848.         } else
  849.             return;    /* still blanked */
  850.     }
  851.     XFreePixmap(text);
  852.     XUnmapWindow(black);
  853.     XMapWindow(icon);
  854.     idletimeout.tv_sec = idletime;
  855.     timeout = screensave ? &idletimeout : NULL;
  856.     if(imagepm)
  857.         seticonalarm();
  858. }
  859.  
  860. /*
  861.  * refreshicon() draws the icon in the icon window.
  862.  */
  863. refreshicon()
  864. {
  865.     newtimestr();
  866.     XPixmapPut(icon, iconx, 0, DELTA, DELTA, bitmap_width, bitmap_height,
  867.      (imagepm && !amicon) ? imagepm : image, GXcopy, AllPlanes);
  868. }
  869.  
  870. /*
  871.  * domenu() handles the icon menu.
  872.  */
  873. domenu(reply)
  874. register XKeyOrButtonEvent *reply;
  875. {
  876.     register char **ptr;
  877.     register int item, l = autolock;
  878.     static int inited;
  879.     static int wasscreensave;
  880.     static int wasautolock;
  881.     extern int justexpose();
  882.  
  883.     if(!inited) {
  884.         extern Cursor Menu_DefaultCursor;
  885.  
  886.         inited++;
  887.         InitMenu(myname);
  888.         if(arrow)
  889.             Menu_DefaultCursor = arrow;
  890.     }
  891.     if (menu == NULL) {
  892.         if ((menu = NewMenu("ScreenSaver", 0)) == NULL)
  893.             fatal("Can't create menu");
  894.         for(ptr = mtext ; *ptr ; ptr++)
  895.             AddMenuItem(menu, *ptr);
  896.         if(wasscreensave = screensave)
  897.             CheckItem(menu, MENU_ONOFF);
  898.         if(wasautolock = autolock)
  899.             CheckItem(menu, MENU_AUTOLOCK);
  900.         DisableItem(menu, MENU_LINE);
  901.         DisableItem(menu, MENU_LINE2);
  902.     } else {
  903.         if(wasscreensave != screensave)
  904.             SetItemCheck(menu, MENU_ONOFF, (wasscreensave =
  905.              screensave));
  906.         if(wasautolock != autolock)
  907.             SetItemCheck(menu, MENU_AUTOLOCK, (wasautolock =
  908.              autolock));
  909.     }
  910.     SetMenuEventHandler(menu, justexpose);
  911.     if((item = TrackMenu(menu, reply)) < 0)
  912.         return(0);
  913.     switch (item) {
  914.      case MENU_ONOFF:
  915.         timeout = (screensave = !screensave) ? &idletimeout : NULL;
  916.         return(0);
  917.      case MENU_AUTOLOCK:
  918.         autolock = !autolock;
  919.         return(0);
  920.      case MENU_LOCK:
  921.         l = TRUE;
  922.          /* drop through */
  923.      case MENU_BLANK:
  924.         timeout = &idletimeout;
  925.         XUnmapWindow(icon);
  926.         blank(l);
  927.         return(IMAGESPERSEC);
  928.      case MENU_EXIT:
  929.         exit(0);
  930.     }
  931. }
  932.  
  933. /*
  934.  * justexpose() just handles exposure events for the icon when doing the menu.
  935.  */
  936. justexpose(ev)
  937. XEvent *ev;
  938. {
  939.     if(ev->type == ExposeWindow)
  940.         refreshicon();
  941. }
  942.  
  943. /*
  944.  * tryagain() finds the most recently written to master end of a pty.  If
  945.  * the idle time has since elapsed, zero is returned.  Otherwise, it returns
  946.  * the amount of time to wait until checking again.  If X_input_fd >= 0,
  947.  * then check this file descriptor only (assumed that the server is modifying
  948.  * this file everytime it gets input).
  949.  */
  950. tryagain()
  951. {
  952.     static int idlecount = 0;
  953.     static char group[] = "pqrstuvw";
  954.     static char single[] = "0123456789abcdef";
  955.     static char pty[] = "/dev/pty??";
  956.     register char *g, *s;
  957.     register long ltime;
  958.     register int i, mintime;
  959.     struct stat sbuf;
  960.  
  961.     ltime = time((long *)0);
  962.     if(X_input_fd >= 0 && fstat(X_input_fd, &sbuf) == 0)
  963.         mintime = ltime - sbuf.st_ctime;
  964.     else {
  965.         mintime = 2 * idletime;
  966.         for(g = group ; *g ; g++) {
  967.             pty[8] = *g;
  968.             for(s = single ; *s ; s++) {
  969.                 pty[9] = *s;
  970.                 if(stat(pty, &sbuf) < 0)
  971.                     break;    /* skip rest of sequence */
  972.                 if((i = ltime - sbuf.st_mtime) < 0) {
  973.                     if(-i > idletime)
  974.                         continue;
  975.                     i = 0;
  976.                 }
  977.                 if(i < mintime)
  978.                     mintime = i;
  979.             }
  980.         }
  981.     }
  982.     return((i = idletime - mintime) <= 0 ? 0 : i);
  983. }
  984.  
  985. /*
  986.  * blank() maps a black window over the screen and sets up the image and
  987.  * time string.  If wantlock is TRUE, locking will occur if checklogin() also
  988.  * returns TRUE.
  989.  */
  990. blank(wantlock)
  991. int wantlock;
  992. {
  993.     register int i;
  994.  
  995.     /*
  996.      * Turn off icon alarm, if on.
  997.      */
  998.     if(imagepm) {
  999.         bzero((char *)&timer, sizeof(timer));
  1000.         setitimer(ITIMER_REAL, &timer, (struct itimerval *)NULL);
  1001.     }
  1002.     /*
  1003.      * Get rid of any left over events.
  1004.      */
  1005.     XSync(TRUE);
  1006.     /*
  1007.      * Map the window.
  1008.      */
  1009.     XMapWindow(black);
  1010.     /*
  1011.      * Set locked if requested and someone is logged in.  If then, we can't
  1012.      * grab the mouse, return.
  1013.      */
  1014.     if(wantlock && (locked = checklogin()) &&
  1015.      !XGrabMouse(black, blackcursor, KeyPressed | ButtonPressed |
  1016.      ButtonReleased | ExposeWindow | UnmapWindow)) {
  1017.         XUnmapWindow(black);
  1018.         XMapWindow(icon);
  1019.         (timeout = &idletimeout)->tv_sec = idletime;
  1020.         return;
  1021.     }
  1022.     /*
  1023.      * Pick a random place on the screen to start.
  1024.      */
  1025.     x0 = random() % areawidth;
  1026.     y0 = random() % areaheight;
  1027.     /*
  1028.      * Initialize and then pick a random direction to go in.
  1029.      */
  1030.     xlast = x0;
  1031.     ylast = y0;
  1032.     rancnt = 0;
  1033.     step = 0;
  1034.     newdirection(random() % NWALLS);
  1035.     /*
  1036.      * Make a Pixmap of the time.
  1037.      */
  1038.     newtimestr();
  1039.     XRaiseWindow(black);    /* make sure we're on top */
  1040.     XText(black, x0 + timemove + center + DELTA, y0 + DELTA, timestr,
  1041.      strlen(timestr), font, WhitePixel, BlackPixel);
  1042.     if((text = XPixmapSave(black, x0, y0, imagewidth, fontheight)) ==
  1043.      (Pixmap)0)
  1044.         fatal("Can't make time image");
  1045.     newtime = 0;
  1046.     XPixmapPut(black, 0, 0, x0, y0 + fontheight, imagewidth, imageheight,
  1047.      (imagepm && !am) ? imagepm : image, GXcopy, AllPlanes);
  1048.     timeout = &movetimeout;
  1049. }
  1050.  
  1051. /*
  1052.  * setupimage() reads in the bitmap(s) and draws it on the screen at x0, y0.
  1053.  * The width and height of the image is returned.  If nodefault is set, zero
  1054.  * is returned if the file can't be opened.
  1055.  */
  1056. setupimage(file, width, height, head, nodefault)
  1057. char *file;
  1058. int *width, *height;
  1059. struct bm **head;
  1060. int nodefault;
  1061. {
  1062.     register FILE *fp;
  1063.     register int totalw, totalh;
  1064.     register char *cp;
  1065.     register struct bm **bp = head;
  1066.     int w, h, x, y;
  1067.     short *bits;
  1068.     char color[64];
  1069.     char name[128];
  1070.     char line[BUFSIZ];
  1071.     Color col;
  1072.  
  1073.     /*
  1074.      * Read the bitmap file into bitmap_bits.
  1075.      */
  1076.     switch(XReadBitmapFile(file, &w, &h, &bits, NULL, NULL)) {
  1077.      case BITMAPOPENERR:
  1078. defaultimage:
  1079.         if(nodefault)
  1080.             return(FALSE);
  1081.         if((*bp = (struct bm *)calloc(1, sizeof(struct bm))) == NULL)
  1082.             fatal("Out of memory for bitmap structure");
  1083.         *width = (*bp)->width = DEFAULTWIDTH;
  1084.         *height = (*bp)->height = DEFAULTHEIGHT;
  1085.         (*bp)->color = WhitePixel;
  1086.         return(TRUE);
  1087.      case BITMAPOK:
  1088.         if((*bp = (struct bm *)calloc(1, sizeof(struct bm))) == NULL)
  1089.             fatal("Out of memory for bitmap structure");
  1090.         *width = (*bp)->width = w;
  1091.         *height = (*bp)->height = h;
  1092.         (*bp)->bits = bits;
  1093.         (*bp)->color = WhitePixel;
  1094.         return(TRUE);
  1095.     }
  1096.     /*
  1097.      * Assume that the file is a bitmap list file.
  1098.      */
  1099.     if((fp = fopen(file, "r")) == NULL)
  1100.         goto defaultimage;
  1101.     totalh = totalw = 0;
  1102.     strcpy(name, file);
  1103.     if(cp = rindex(name, '/'))
  1104.         cp++;
  1105.     else
  1106.         cp = name;
  1107.     while(fgets(line, sizeof(line), fp)) {
  1108.         if(*line == '#')    /* comment */
  1109.             continue;
  1110.         if(sscanf(line, "%s %s %d %d", cp, color, &x, &y) != 4)
  1111.             continue;
  1112.         if(XReadBitmapFile(name, &w, &h, &bits, NULL, NULL) != BITMAPOK)
  1113.             continue;
  1114.         if((*bp = (struct bm *)calloc(1, sizeof(struct bm))) == NULL)
  1115.             fatal("Out of memory for bitmap structure");
  1116.         (*bp)->x = x;
  1117.         (*bp)->y = y;
  1118.         (*bp)->width = w;
  1119.         (*bp)->height = h;
  1120.         (*bp)->bits = bits;
  1121.         if(DisplayCells() > 2) {
  1122.             if(!XParseColor(color, &col) ||
  1123.              !XGetHardwareColor(&col))
  1124.                 col.pixel = WhitePixel;
  1125.         } else
  1126.             col.pixel = (strcmp(color, "black") == 0) ? BlackPixel :
  1127.              WhitePixel;
  1128.         (*bp)->color = col.pixel;
  1129.         if((w += x) > totalw)
  1130.             totalw = w;
  1131.         if((h += y) > totalh)
  1132.             totalh = h;
  1133.         bp = &(*bp)->next;
  1134.     }
  1135.     fclose(fp);
  1136.     if(totalw <= 0 || totalh <= 0) {
  1137.         if(bp != head)
  1138.             freebm(*head);
  1139.         goto defaultimage;
  1140.     }
  1141.     *width = totalw;
  1142.     *height = totalh;
  1143.     return(TRUE);
  1144. }
  1145.  
  1146. freebm(bp)
  1147. register struct bm *bp;
  1148. {
  1149.     register struct bm *np;
  1150.  
  1151.     while(bp) {
  1152.         np = bp->next;
  1153.         free((char *)bp);
  1154.         bp = np;
  1155.     }
  1156. }
  1157.  
  1158. /*
  1159.  * drawimage draws the actual image, after each timeout.
  1160.  */
  1161. drawimage()
  1162. {
  1163.     register int x, y;
  1164.  
  1165.     /*
  1166.      * Step along in the current direction.  If we hit an edge,
  1167.      * calculate another direction to go in (bounce off).  The loop
  1168.      * is just in case we are in a corner and would go off in the
  1169.      * wrong direction.
  1170.      */
  1171.     for( ; ; step = 0) {
  1172.         step += DELTA;
  1173.         x = xmove(step);
  1174.         y = ymove(step);
  1175.         if(x < 0) {
  1176.             newdirection(LEFT);
  1177.             continue;
  1178.         }
  1179.         if(y < 0) {
  1180.             newdirection(TOP);
  1181.             continue;
  1182.         }
  1183.         if(x >= areawidth) {
  1184.             newdirection(RIGHT);
  1185.             continue;
  1186.         }
  1187.         if(y >= areaheight) {
  1188.             newdirection(BOTTOM);
  1189.             continue;
  1190.         }
  1191.         break;
  1192.     }
  1193.     /*
  1194.      * Draw the image and the time string.
  1195.      */
  1196.     xlast = x;
  1197.     ylast = y;
  1198.     if(newtime) {
  1199.         XPixSet(black, x, y, imagewidth, fontheight, BlackPixel);
  1200.         XText(black, x + timemove + center + DELTA, y + DELTA, timestr,
  1201.          strlen(timestr), font, WhitePixel, BlackPixel);
  1202.         XFreePixmap(text);
  1203.         if((text = XPixmapSave(black, x, y, imagewidth, fontheight)) ==
  1204.          (Pixmap)0)
  1205.             fatal("Can't make time image");
  1206.         newtime = 0;
  1207.     } else
  1208.         XPixmapPut(black, 0, 0, x, y, imagewidth, fontheight, text,
  1209.          GXcopy, AllPlanes);
  1210.     XPixmapPut(black, 0, 0, x, y + fontheight, imagewidth, imageheight,
  1211.      (imagepm && !am) ? imagepm : image, GXcopy, AllPlanes);
  1212. }
  1213.  
  1214. /*
  1215.  * newdirection() calculates a random direction to go in, after encountering
  1216.  * a wall.  sinindex is the index into the sin1000[] array, which is used to
  1217.  * calculate the sin and cosine of the trajectory.  Since sin1000[] is for
  1218.  * quadrant one, we have signx and signy to move in all four quadrants.
  1219.  */
  1220. newdirection(wall)
  1221. {
  1222.     if(rancnt-- <= 0) {
  1223.         sinindex = random() % SINN;
  1224.         rancnt = random() % RANCNTMAX;
  1225.     }
  1226.     switch(wall) {
  1227.      case LEFT:
  1228.         signx = 1;
  1229.         break;
  1230.      case TOP:
  1231.         signy = 1;
  1232.         break;
  1233.      case RIGHT:
  1234.         signx = -1;
  1235.         break;
  1236.      case BOTTOM:
  1237.         signy = -1;
  1238.         break;
  1239.     }
  1240.     x0 = xlast;
  1241.     y0 = ylast;
  1242. }
  1243.  
  1244. /*
  1245.  * newtimestr() makes a new time string.
  1246.  */
  1247. newtimestr()
  1248. {
  1249.     register struct tm *tp;
  1250.     register int hour;
  1251.     static int hr = -1;
  1252.     static int minute = -1;
  1253.     long t;
  1254.  
  1255.     time(&t);
  1256.     tp = localtime(&t);
  1257.     am = 1;
  1258.     if((hour = tp->tm_hour) >= 12) {
  1259.         if(hour > 12)
  1260.             hour -= 12;
  1261.         am = 0;
  1262.     } else if(hour == 0)
  1263.         hour = 12;
  1264.     if(tp->tm_min == minute && hr == hour)
  1265.         return;
  1266.     sprintf(timestr, "%d:%02d", hr = hour, minute = tp->tm_min);
  1267.     center = hr < 10 ? halfwidth : 0;
  1268.     newtime++;
  1269. }
  1270.  
  1271. /*
  1272.  * fatal() prints an error message, either to the stderr or to /dev/console
  1273.  * and then exits.
  1274.  */
  1275. fatal(str)
  1276. char *str;
  1277. {
  1278.     if(console || (console = fopen("/dev/console", "w")))
  1279.         fprintf(console, "%s: %s\n", myname, str);
  1280.     exit(1);
  1281. }
  1282.  
  1283. /*
  1284.  * verify() displays a password dialog box and if the typed in password is
  1285.  * correct, returns TRUE.  If the password is not completed in VERIFYTIMEOUT
  1286.  * seconds the box disappears and FALSE is returned.  But is checklogin()
  1287.  * returns FALSE, we return TRUE so that we allow new logins.
  1288.  */
  1289. verify()
  1290. {
  1291.     register char *cp, *bp;
  1292.     register int fh, x, y, w, h, x0, y0, status = FALSE;
  1293.     int i;
  1294.     char pstr[32];
  1295.     XEvent ev;
  1296.     char *crypt();
  1297.  
  1298. #ifdef DEBUG
  1299.     fputs("In verify()\n", stderr);
  1300. #endif DEBUG
  1301.     if(!checklogin())
  1302.         return(TRUE);
  1303. #ifndef DEBUG
  1304.     XGrabServer();
  1305. #else DEBUG
  1306.     fputs("checklogin returns TRUE\n", stderr);
  1307. #endif DEBUG
  1308.     if((i = XStringWidth(pw->pw_name, finfo, 0, 0) + userwidth)
  1309.      < passwordwidth)
  1310.         i = passwordwidth;
  1311.     w = i + 2 * (fh = finfo->height);
  1312.     h = 5 * fh;
  1313.     x0 = (DisplayWidth() - w) / 2;
  1314. #ifdef DEBUG
  1315.     y0 = (DisplayHeight() / 2 - h) / 2;
  1316. #else DEBUG
  1317.     y0 = (DisplayHeight() - h) / 2;
  1318. #endif DEBUG
  1319.     XRaiseWindow(black);
  1320.     XPixSet(black, x0, y0, w, h, WhitePixel);
  1321.     outline[0].x = x0 - 3;
  1322.     outline[0].y = y0 - 3;
  1323.     outline[3].x = -(outline[1].x = w + 5);
  1324.     XDraw(black, outline, 5, 1, 1, WhitePixel, GXcopy, AllPlanes);
  1325.     XTextMask(black, x = x0 + fh, y = y0 + fh, user, USERLEN,
  1326.      font, BlackPixel);
  1327.     XTextMask(black, x + userwidth, y, pw->pw_name, strlen(pw->pw_name),
  1328.      font, BlackPixel);
  1329.     XTextMask(black, x, y += 2 * fh, password, PASSWORDLEN, font,
  1330.      BlackPixel);
  1331.     XPixSet(black, x + passwordwidth - spacewidth, y, spacewidth,
  1332.      fh, BlackPixel);
  1333.     XSync(TRUE);
  1334.     bzero((char *)&timer, sizeof(timer));
  1335.     timer.it_value = verifytimeout;
  1336.     setitimer(ITIMER_REAL, &timer, (struct itimerval *)NULL);
  1337.     if(setjmp(verifyjmp) == 0) {
  1338.         for(cp = pstr, x = sizeof(pstr) - 1 ; ; ) {
  1339.             XNextEvent(&ev);
  1340.             if(ev.type != KeyPressed)
  1341.                 continue;
  1342.             bp = XLookupMapping(&ev, &i);
  1343.             if(i <= 0)
  1344.                 continue;
  1345.             while(i-- > 0) {
  1346.                 if(*bp == '\r' || *bp == '\n') {
  1347.                     *cp = 0;
  1348.                     if(!(status = (strcmp(pw->pw_passwd,
  1349.                      crypt(pstr, pw->pw_passwd)) == 0)) &&
  1350.                      *rootpasswd)
  1351.                         status = (strcmp(rootpasswd,
  1352.                          crypt(pstr, rootpasswd)) == 0);
  1353. #ifdef DEBUG
  1354.                     fprintf(stderr, "password %s\n",
  1355.                      status ? "matches" : "doesn't match");
  1356. #endif DEBUG
  1357.                     bp = NULL;    /* break out */
  1358.                     break;
  1359.                 }
  1360.                 if(x > 0) {
  1361.                     *cp++ = *bp;
  1362.                     x--;
  1363.                 }
  1364.                 bp++;
  1365.             }
  1366.             if(bp == NULL)
  1367.                 break;
  1368.         }
  1369.     }
  1370.     bzero((char *)&timer, sizeof(timer));
  1371.     setitimer(ITIMER_REAL, &timer, (struct itimerval *)NULL);
  1372.     XPixSet(black, x0 - 3, y0 - 3, w + 6, h + 6, BlackPixel);
  1373. #ifndef DEBUG
  1374.     XUngrabServer();
  1375. #endif DEBUG
  1376.     XSync(TRUE);
  1377.     return(status);
  1378. }
  1379.  
  1380. /*
  1381.  * onalarm() is called when the VERIFYTIMEOUT period has expired.
  1382.  */
  1383. onalarm()
  1384. {
  1385.     if(timeout == &movetimeout) {
  1386.         if(timer.it_value.tv_sec == 0)    /* stray alarm */
  1387.             return;
  1388. #ifdef DEBUG
  1389.         fputs("In onalarm() verify\n", stderr);
  1390. #endif DEBUG
  1391.         longjmp(verifyjmp, TRUE);
  1392.     } else if(imagepm) {
  1393.         seticonalarm();
  1394.         refreshicon();
  1395.     }
  1396. }
  1397.  
  1398. /*
  1399.  * checklogin() sees if someone is logged into tty.  If tty is not set,
  1400.  * TRUE is always returned.
  1401.  */
  1402. checklogin()
  1403. {
  1404.     register FILE *fp;
  1405.     struct utmp utmp;
  1406.  
  1407. #ifdef DEBUG
  1408.     fputs("In checklogin()\n", stderr);
  1409. #endif DEBUG
  1410.     if(!tty)
  1411.         return(TRUE);
  1412.     if((fp = fopen("/etc/utmp", "r")) == NULL)
  1413.         return(FALSE);
  1414.     for( ; ; ) {
  1415.         if(fread((char *)&utmp, sizeof(utmp), 1, fp) <= 0) {
  1416.             fclose(fp);
  1417.             return(FALSE);
  1418.         }
  1419.         if(strcmp(tty, utmp.ut_line) == 0) {
  1420.             fclose(fp);
  1421.             if(*utmp.ut_name)    /* someone logged in */
  1422. #ifdef DEBUG
  1423.             {
  1424.                 fprintf(stderr, "%s logged in\n", utmp.ut_name);
  1425.                 break;
  1426.             }
  1427. #else DEBUG
  1428.                 break;
  1429. #endif DEBUG
  1430.             return(FALSE);
  1431.         }
  1432.     }
  1433.     pw = getpwnam(utmp.ut_name);
  1434.     endpwent();
  1435.     return(pw != NULL && *pw->pw_passwd);
  1436. }
  1437.  
  1438. /*
  1439.  * seticonalarm() sets an alarm signal to redraw the icon (am <-> pm).
  1440.  */
  1441. seticonalarm()
  1442. {
  1443.     register struct tm *tp;
  1444.     struct itimerval itimer;
  1445.     long t;
  1446.  
  1447.     time(&t);
  1448.     tp = localtime(&t);
  1449.     am = 1;
  1450.     if(tp->tm_hour >= 12) {
  1451.         tp->tm_hour -= 12;
  1452.         amicon = FALSE;
  1453.     } else
  1454.         amicon = TRUE;
  1455.     bzero((char *)&itimer, sizeof(itimer));
  1456.     itimer.it_value.tv_sec = 60 * (60 * (12 - tp->tm_hour) - tp->tm_min) -
  1457.      tp->tm_sec;
  1458.     setitimer(ITIMER_REAL, &itimer, (struct itimerval *)NULL);
  1459. }
  1460. RAZZLE!DAZZLE
  1461. fi    # End screensaver.c
  1462. echo '***** End of' screensaver for X window system - part 2 of 2 '*****'
  1463. exit
  1464.  
  1465.